#ifndef CONTROL_SIGNAL_DISPATCHER_H_INCLUDED
#define CONTROL_SIGNAL_DISPATCHER_H_INCLUDED

#include <control_dispatcher.h>
#include <control_terminal.h>

#include <sys/signalfd.h>
#include <cerrno>
#include <unistd.h>

#include <utils/signal_blocker.h>
#include <utils/system_exception.h>

class ControlTerminal::SignalDispatcher
    : public ControlDispatcher
{
public:
    explicit SignalDispatcher(utils::signal_blocker const & blocker)
        : fd_(::signalfd(-1, &blocker.mask(), SFD_NONBLOCK))
    {
        if(fd_ < 0)
        {
            throw utils::system_exception(errno);
        }
    }

    /*virtual*/
    bool dispatch(ControlTerminal & term)
    {
        ::signalfd_siginfo fdsi;

        int const r = ::read(fd_, &fdsi, sizeof(fdsi));
        if(r != sizeof(fdsi))
        {
            throw utils::system_exception(errno);
        }
        return term.onSignal(fdsi.ssi_signo);
    }

    int fd() const
    {
        return fd_;
    }

    /*virtual*/
    ~SignalDispatcher() throw()
    {
        ::close(fd_);
    }

private:
    int const fd_;
};

#endif // CONTROL_SIGNAL_DISPATCHER_H_INCLUDED
